use std::sync::atomic::{AtomicI64, Ordering};

use crate::{archetype::Archetype, component::{ComponentTrait, get_component_id}, MangoEcsError};


#[derive(Debug,Clone, Copy,Hash,PartialEq, PartialOrd,Eq, Ord)]
pub struct Entity {
    pub(crate) index:u32,
    pub(crate) generation:u32
}


impl Entity {
    pub fn index(&self) -> u32 { self.index }
    pub fn generation(&self) -> u32 { self.generation }
    pub fn to_u64(self) -> u64 {
        u64::from(self.generation) << 32 | u64::from(self.index)
    }
    pub fn from_u64(num:u64) -> Self {
        Self {
            generation:(num >> 32) as u32,
            index:num as u32
        }
    }
}

/// 
/// [`Entity`] 存储在 ECS 世界[`World`]中的位置
/// 
#[derive(Debug,Clone, Copy)]
pub struct EntityLocation {
    /// 所在的 [`Archetype`] 在[`World`]中的的位置
    pub archetype_index:usize,
    /// 自身在所在的[`Archetype`]中的位置
    pub index_within_archetype:usize
}

///
/// 实体的可变引用
/// 
pub struct EntityRef<'e> {
    /// 实体所在的 archetype
    archetype:&'e mut Archetype,
    /// 实体在archetype中的 位置索引
    index_within_archetype:usize
}

impl<'e> EntityRef<'e> {
    pub fn get_mut<C:ComponentTrait>(&mut self) -> Result<&mut C,MangoEcsError> {
        let cmp_id = get_component_id::<C>();
        for chinnal in &mut self.archetype.channels {
            if chinnal.component_id == cmp_id {
                let component = &mut chinnal.as_mut_vec()[self.index_within_archetype];

                return Ok(component);
            }
        }
        Err(MangoEcsError::no_matching_component::<C>())
    }
}



///
/// 控制实体到 Archetype 的映射
/// 
#[derive(Debug)]
pub struct Entities {
    /// 如果 entity location 为 None 则实体已经被销毁
    generation_and_entity_location:Vec<(u32,Option<EntityLocation>)>,
    /// 已经释放的实体集合,可以在下一次创建实体时复用
    pub(crate) free_entities:Vec<Entity>,
    /// 处于销毁状态可以在下一次创建实体时被复用的实体数量, 如果小于0,则表示不存在可以复用的实体
    pub(crate) available_free_indices:AtomicI64
}   

impl Default for Entities {
    fn default() -> Self {
        Self {
            generation_and_entity_location: vec![],
            free_entities: vec![],
            available_free_indices:AtomicI64::new(0),
        }
    }
}

impl Entities {
    /// 从另外的 Entitie 中复制存活中的实体
    pub fn reserve_space_for_entity_cloning(&mut self,other:&Entities) {

        self.generation_and_entity_location
            .reserve(other.generation_and_entity_location.len() - other.free_entities.len());

        let entities_to_reserve = other.generation_and_entity_location.len() - other.free_entities.len() - self.free_entities.len();

        self.generation_and_entity_location.extend((0..entities_to_reserve).map(|_|(0,None)));
    }

    /// 从指定的实体位置创建一个实体
    pub fn new_entity(&mut self, location:Option<EntityLocation>) -> Entity {
        if let Some(free_entity) = self.free_entities.pop() {
            self.generation_and_entity_location[free_entity.index as usize] = (free_entity.generation,location);

            free_entity
        }else {
            self.generation_and_entity_location.push((0,location));
            Entity {
                index: self.generation_and_entity_location.len() as u32 - 1,
                generation: 0,
            }
        }
    }   

    /// 获取实体对应的位置
    pub fn get_entity_location(&self,entity:Entity) -> Option<EntityLocation> {
        let (g,l) = &self.generation_and_entity_location[entity.index as usize];
        if *g != entity.generation {
            None
        }else {
            *l
        }
    }

    /// 获取实体位置,不检查实体位置是否正确
    pub fn get_entity_location_mut(&mut self,entity:Entity) -> &mut Option<EntityLocation> {
        &mut self.generation_and_entity_location[entity.index as usize].1
    }

    /// 释放实体同时允许重用实体的索引
    pub fn free(&mut self,entity:Entity) -> Result<EntityLocation,MangoEcsError> {
        if let Some((g,l))= self.generation_and_entity_location.get_mut(entity.index as usize) {
            if *g == entity.generation {
                if let Some(l) = l.take() {
                    self.free_entities.push(Entity {
                        index: entity.index,
                        // todo ???? 旧的generation已经过期?
                        generation: entity.generation + 1,
                    });
                    *self.available_free_indices.get_mut() += 1;
                    return Ok(l);
                }
            }
        }

        Err(MangoEcsError::EntityMissing)
    }

    ///
    /// ????
    /// 保留一个实体,他的实体位置在稍后将被分配,这是为了不占用 World 的所有权的
    /// 情况下创建 Entity 句柄
    /// 
    pub fn reserve(&self) -> Entity {
        let available_index = self.available_free_indices.fetch_sub(1, Ordering::Relaxed);
        if available_index > 0 {
            self.free_entities[(available_index - 1) as usize]
        }else {
            Entity {
                index:(self.generation_and_entity_location.len() as i64 - available_index) as u32,
                generation:0
            }
        }

    }

    pub fn instantiate_reserved_entity(&mut self, index_within_archetype:usize) -> Option<Entity> {
        let av = *self.available_free_indices.get_mut();
        if av < self.free_entities.len() as i64 {
            if av < 0 {
                *self.available_free_indices.get_mut() += 1;
            }

            Some(self.new_entity(Some(EntityLocation {
                archetype_index: 0,
                index_within_archetype,
            })))
        }else {
            None
        }
    }

    /// 获取当前 entities 中仍然存活的实体数量
    pub fn len(&self) -> usize {
        self.generation_and_entity_location.len() - self.free_entities.len()
    }




}

///
///  移动实体的上下文
pub struct EntityMigrator {
    free_entities:Vec<Entity>,
    offset:u32
}

impl EntityMigrator {
    pub fn new(free_entities:&[Entity],offset:u32) -> Self {
        Self {
            free_entities:free_entities.into(),
            offset
        }
    }    

    /// 移动实体
    pub fn migrate(&self,old_entity:Entity) -> Entity {
        if old_entity.index < self.free_entities.len() as u32 {
            self.free_entities[self.free_entities.len() - old_entity.index as usize]
        }else {
            Entity {
                generation:0,
                index:self.offset + (old_entity.index - self.free_entities.len() as u32)
            }
        }
    }
}









